package com.example.gobang.socket;

import com.example.gobang.constant.Constants;
import com.example.gobang.game.Matcher;
import com.example.gobang.manager.OnlineUserManager;
import com.example.gobang.model.MatchRequest;
import com.example.gobang.model.MatchResponse;
import com.example.gobang.model.Result;
import com.example.gobang.model.UserInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

@Component
@Slf4j
public class MatchSocket extends TextWebSocketHandler {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Autowired
    private OnlineUserManager onlineUserManager;
    @Autowired
    private Matcher matcher;
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 判定用户是否在线
        UserInfo userInfo = (UserInfo) session.getAttributes().get(Constants.USER);
        // 未登录，返回
        if(userInfo == null) {
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(Result.noLogin())));
            return;
        }
        // 在线，判定当前用户是否已经登录（已经是在线状态），若已在线，则不能继续进行后续逻辑
        WebSocketSession loginSession = onlineUserManager.getFromGameHall(userInfo.getUserId());
        if(onlineUserManager.getFromGameRoom(userInfo.getUserId()) != null
                || onlineUserManager.getFromGameHall(userInfo.getUserId()) != null) {
            // 当前用户已经登录
            // 告知用户禁止重复登录
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(Result.repeatConnection())));
            log.info("已禁止玩家 " + userInfo.getUserName() + " 多开游戏！");
            session.close();
            return;
        }
        // 拿到用户身份信息，并将用户信息设置为在线状态
        onlineUserManager.enterGameHall(userInfo.getUserId(), session);
        log.info("玩家：" + userInfo.getUserName() + " 进入游戏大厅！");
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 处理开始匹配和停止匹配请求
        UserInfo userInfo = (UserInfo) session.getAttributes().get(Constants.USER);
        // 未登录，返回
        if(userInfo == null) {
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(Result.noLogin())));
            return;
        }
        // 获取到客户端发送给服务器的请求数据
        String payload = message.getPayload();
        // 将 JSON 格式的字符串，转换成Java对象
        MatchRequest request = objectMapper.readValue(payload, MatchRequest.class);
        Result result = new Result();
        if(request.getMessage().equals(Constants.START_MATCH)) {
            // 进入匹配队列
            matcher.add(userInfo);
            // 告诉用户已经开始匹配
            result.setStatus(Constants.START_MATCH);
            result.setErrorMessage("");
            result.setData("开始匹配");
            log.info("玩家 {} 进入匹配队列", userInfo.getUserName());
        }else if(request.getMessage().equals(Constants.STOP_MATCH)) {
            // 取消匹配，退出匹配队列
            matcher.remove(userInfo);
            // 告诉用户已经取消匹配
            result.setStatus(Constants.STOP_MATCH);
            result.setData("取消匹配");
            result.setErrorMessage("");
            log.info("玩家 {} 已从匹配队列移除", userInfo.getUserName());
        }else {
            result.setStatus(Constants.FAIL);
            result.setErrorMessage("非法的匹配请求");
        }
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(result)));
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        // 玩家下线，从 OnlineUserManager 中删除
        UserInfo userInfo = (UserInfo) session.getAttributes().get(Constants.USER);
        // 未登录，返回
        if(userInfo == null) {
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(Result.noLogin())));
            return;
        }
        // 判定是否是多开情况
        WebSocketSession loginSession = onlineUserManager.getFromGameHall(userInfo.getUserId());
        if(loginSession == session) {
            onlineUserManager.exitGameHall(userInfo.getUserId());
            log.info("handleTransportError 玩家：" + userInfo.getUserName() + " 已离开游戏大厅！");
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        // 玩家下线，从 OnlineUserManager 中删除
        UserInfo userInfo = (UserInfo) session.getAttributes().get(Constants.USER);
        // 未登录，返回
        if(userInfo == null) {
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(Result.noLogin())));
            return;
        }
        // 判定是否是多开情况
        WebSocketSession loginSession = onlineUserManager.getFromGameHall(userInfo.getUserId());
        if(loginSession == session) {
            onlineUserManager.exitGameHall(userInfo.getUserId());
            log.info("afterConnectionClosed 玩家：" + userInfo.getUserName() + " 已离开游戏大厅！");
        }
    }
}
